/***********************************************************************
* Microsoft (R) Windows (R) Resource Compiler
*
* Copyright (c) Microsoft Corporation.  All rights reserved.
*
* File Comments:
*
*
***********************************************************************/

#include "rc.h"

/************************************************************************/
/* Local Function Prototypes                                            */
/************************************************************************/
long and(void);
long andif(void);
long constant(void);
long constexpr(void);
long eqset(void);
long mult(void);
long or(void);
long orelse(void);
long plus(void);
long prim(void);
long relation(void);
long shift(void);
long xor(void);


/************************************************************************/
/* File Global Variables                                                */
/************************************************************************/
long    Currval = 0;
static  int             Parencnt = 0;


/************************************************************************/
/* do_constexpr()                                                       */
/************************************************************************/
long
do_constexpr(
    void
    )
{
    REG long    val;

    Parencnt = 0;
    Currtok = L_NOTOKEN;
    val = constexpr();
    if( Currtok == L_RPAREN ) {
        if( Parencnt-- == 0 ) {
            fatal(1012, L"(");                /* missing left paren */
        }
    } else if( Currtok != L_NOTOKEN ) {
        warning(4067, PPifel_str);
    }

    if( Parencnt > 0 ) {
        fatal(4012, L")");    /* missing right paren */
    }
    return(val);
}

/************************************************************************/
/* constexpr ::= orelse [ '?' orelse ':' orelse ];                      */
/************************************************************************/
long
constexpr(
    void
    )
{
    REG long            val;
    REG long            val1;
    long                val2;

    val = orelse();
    if( nextis(L_QUEST) ) {
        val1 = orelse();
        if( nextis(L_COLON) )
            val2 = orelse();
        return(val ? val1 : val2);
    }
    return(val);
}


/************************************************************************/
/* orelse ::= andif [ '||' andif ]* ;                                   */
/************************************************************************/
long
orelse(
    void
    )
{
    REG long val;

    val = andif();
    while(nextis(L_OROR))
        val = andif() || val;
    return(val);
}


/************************************************************************/
/* andif ::= or [ '&&' or ]* ;                                          */
/************************************************************************/
long
andif(
    void
    )
{
    REG long val;

    val = or();
    while(nextis(L_ANDAND))
        val = or() && val;
    return(val);
}


/************************************************************************/
/* or ::= xor [ '|' xor]* ;                                             */
/************************************************************************/
long
or(
    void
    )
{
    REG long val;

    val = xor();
    while( nextis(L_OR) )
        val |= xor();
    return(val);
}


/************************************************************************/
/* xor ::= and [ '^' and]* ;                                            */
/************************************************************************/
long
xor(
    void
    )
{
    REG long val;

    val = and();
    while( nextis(L_XOR) )
        val ^= and();
    return(val);
}


/************************************************************************/
/*  and ::= eqset [ '&' eqset]* ;                                       */
/************************************************************************/
long
and(
    void
    )
{
    REG long val;

    val = eqset();
    while( nextis(L_AND) )
        val &= eqset();
    return(val);
}


/************************************************************************/
/* eqset ::= relation [ ('==' | '!=') eqset] ;                          */
/************************************************************************/
long
eqset(
    void
    )
{
    REG long val;

    val = relation();
    if( nextis(L_EQUALS) )
        return(val == relation());
    if( nextis(L_NOTEQ) )
        return(val != relation());
    return(val);
}

/************************************************************************/
/* relation ::= shift [ ('<' | '>' | '<=' | '>=' ) shift] ;             */
/************************************************************************/
long
relation(
    void
    )
{
    REG long val;

    val = shift();
    if( nextis(L_LT) )
        return(val < shift());
    if( nextis(L_GT) )
        return(val > shift());
    if( nextis(L_LTEQ) )
        return(val <= shift());
    if( nextis(L_GTEQ) )
        return(val >= shift());
    return(val);
}


/************************************************************************/
/* shift ::= plus [ ('<< | '>>') plus] ;                                */
/************************************************************************/
long
shift(
    void
    )
{
    REG long val;

    val = plus();
    if( nextis(L_RSHIFT) )
        return(val >> plus());
    if( nextis(L_LSHIFT) )
        return(val << plus());
    return(val);
}


/************************************************************************/
/* plus ::= mult [ ('+' | '-') mult ]* ;                                */
/************************************************************************/
long
plus(
    void
    )
{
    REG long val;

    val = mult();
    for(;;) {
        if( nextis(L_PLUS) )
            val += mult();
        else if( nextis(L_MINUS) )
            val -= mult();
        else
            break;
    }
    return(val);
}


/************************************************************************/
/* mult ::= prim [ ('*' | '/' | '%' ) prim ]* ;                         */
/************************************************************************/
long
mult(
    void
    )
{
    REG long val;
    long PrimVal;

    val = prim();
    for(;;) {
        if( nextis(L_MULT) )
            val *= prim();
        else if( nextis(L_DIV) ) {
            PrimVal = prim();
            if (PrimVal)
                val /= PrimVal;
            else
                val = PrimVal;
        }
        else if( nextis(L_MOD) ) {
            PrimVal = prim();
            if (PrimVal)
                val %= PrimVal;
            else
                val = 0;
        }
        else
            break;
    }
    return(val);
}


/************************************************************************/
/* prim ::= constant | ( '!' | '~' | '-' ) constant                     */
/************************************************************************/
long
prim(
    void
    )
{
    if( nextis(L_EXCLAIM) )
        return( ! constant());
    else if( nextis(L_TILDE) )
        return( ~ constant() );
    else if( nextis(L_MINUS) )
        return(-constant());
    else
        return(constant());
}


/************************************************************************/
/* constant - at last, a terminal symbol  | '(' constexpr ')'           */
/************************************************************************/
long
constant(
    void
    )
{
    REG long val;

    if( nextis(L_LPAREN) ) {
        Parencnt++;
        val = constexpr();
        if( nextis(L_RPAREN) ) {
            Parencnt--;
            return(val);
        } else {
            fatal(1012, L")");
        }
    } else if( ! nextis(L_CINTEGER) ) {
        fatal(1017);    /* invalid integer constant expression */
    }

    return(Currval);
}
